//
// Ishtar C++ Utility Library
//
// Task Facility - Periodic Timer Implementation
//

#include <Ishtar/Pch.h>

#include <Ishtar/Task/PeriodicTimerImpl.h>


namespace Ishtar
{

namespace Task
{

///////////////////////////////////////////////////////////////////////////////
//
// PeriodicTimer
//

ISHTAR_REFERENCE_COUNTED_DEFINE( PeriodicTimerImpl )

PeriodicTimerImpl::PeriodicTimerImpl(
    const std::string& name, const WorkFunction& workFunc, Uint dueTime, Uint period,
    WorkExecutor& executor )
    : m_name( name )
    , m_period( period )
    , m_stopped( false )
    , m_executor( executor )
{
    this->SubmitWorkWrapper( workFunc, dueTime );
}


PeriodicTimerImpl::~PeriodicTimerImpl()
{
    this->Stop();
}


void PeriodicTimerImpl::WorkWrapper( const WorkFunction& workFunc )
{
    Mutex::UniqueLock ulock( m_mutex );

    ExceptionCatcher< void > xc( workFunc );
    if ( xc )
    {
        ISHTAR_TRACE_WARN_HERE( "Work function throws and ignored" );
        ISHTAR_TRACE_INFO( "  workName: %s", m_name );
    }
    
    if ( 0 < m_period && !m_stopped )
    {
        this->SubmitWorkWrapper( workFunc, m_period );
    }
    else
        m_work = Work();
}


void PeriodicTimerImpl::SubmitWorkWrapper( const WorkFunction& workFunc, Uint delay )
{
    m_work = MakeWork( m_name, boost::bind(
        &PeriodicTimerImpl::WorkWrapper, PeriodicTimerImplPtr( this ), workFunc ));
    m_work.DelayFor( delay );
    m_executor.Submit( m_work );
}


Bool PeriodicTimerImpl::Stop()
{
    Mutex::UniqueLock ulock( m_mutex );

    if ( m_stopped ) { return false; }

    m_stopped = true;
    m_work.Cancel();
    m_work = Work();
    
    return true;
}


//
// Bridging
//

PeriodicTimer::PeriodicTimer()
{
}


PeriodicTimer::PeriodicTimer(
    const std::string& name, const WorkFunction& workFunc, Uint dueTime, Uint period,
    WorkExecutor& executor
)
    : m_impl( new PeriodicTimerImpl( name, workFunc, dueTime, period, executor ))
{
}


Bool PeriodicTimer::Stop()
{
    PeriodicTimerImplPtr impl = m_impl.Exchange( PeriodicTimerImplPtr() );
    if ( impl )
    {
        return impl->Stop();
    }
    else
        return false;
}


Bool PeriodicTimer::IsAlive() const
{
    return m_impl;
}


///////////////////////////////////////////////////////////////////////////////

} // namespace Task

} // namespace Ishtar
